#include "deplibUV.h"
#include <stdexcept>
#include <iostream>

thread_local uv_loop_t* DepLibUV::loop{ nullptr };

inline static void onCloseLoop(uv_handle_t* handle) {
	delete reinterpret_cast<uv_loop_t*>(handle);
}

inline static void onWalk(uv_handle_t* handle, void* /*arg*/) {

	if (!uv_is_closing(handle))
	{
		uv_close(handle, onCloseLoop);
	}
}

void DepLibUV::ClassInit()
{
	// NOTE: Logger depends on this so we cannot log anything here.
	DepLibUV::loop = new uv_loop_t;

	const int err = uv_loop_init(DepLibUV::loop);

	if (err != 0) {
        throw std::runtime_error("libuv loop initialization failed");
	}
}

void DepLibUV::ClassDestroy() {

	// Here we should not have any UV handle left. All them should have been
	// already closed+freed. However, in order to not introduce regressions
	// in the future, we check this anyway.
	// More context: https://github.com/versatica/mediasoup/pull/576

	int err;

	uv_stop(DepLibUV::loop);
	uv_walk(DepLibUV::loop, onWalk, nullptr);

	while (true)
	{
		err = uv_loop_close(DepLibUV::loop);

		if (err != UV_EBUSY)
		{
			break;
		}

		uv_run(DepLibUV::loop, UV_RUN_NOWAIT);
	}

	if (err != 0) {
        std::cout << "Failed to close libuv loop: " << uv_err_name(err) << std::endl;
	}
	delete DepLibUV::loop;
}

void DepLibUV::PrintVersion() {
    std::cout << "libuv version: " << uv_version_string() << std::endl;
}

void DepLibUV::RunLoop() {

    if (DepLibUV::loop == nullptr) {
        throw std::runtime_error("libuv loop is not initialized");
    }

	const int ret = uv_run(DepLibUV::loop, UV_RUN_DEFAULT);

    if (ret < 0) {
        throw std::runtime_error("uv_run() failed: " + std::string(uv_err_name(ret)));
    }
}